#include <gtest/gtest.h>
#include "viml/builtin_file.h"
#include "viml/value.h"
#include <fstream>
#include <filesystem>

namespace fs = std::filesystem;

namespace viml {

class BuiltinFileTest : public ::testing::Test {
protected:
    void SetUp() override {
        // 创建测试目录
        test_dir = "test_file_ops";
        if (fs::exists(test_dir)) {
            fs::remove_all(test_dir);
        }
        fs::create_directory(test_dir);
    }

    void TearDown() override {
        // 清理测试目录
        if (fs::exists(test_dir)) {
            fs::remove_all(test_dir);
        }
    }

    std::string test_dir;
};

// ========================================
// 文件读写测试
// ========================================

TEST_F(BuiltinFileTest, FileWriteAndRead) {
    std::string path = test_dir + "/test.txt";
    std::string content = "Hello, World!";
    
    // 写入文件
    auto write_result = file_write_builtin({Value::string(path), Value::string(content)});
    EXPECT_TRUE(write_result.is_boolean());
    EXPECT_TRUE(write_result.as_boolean());
    
    // 读取文件
    auto read_result = file_read_builtin({Value::string(path)});
    EXPECT_TRUE(read_result.is_string());
    EXPECT_EQ(read_result.as_string(), content);
}

TEST_F(BuiltinFileTest, FileAppend) {
    std::string path = test_dir + "/append.txt";
    
    file_write_builtin({Value::string(path), Value::string("Line 1\n")});
    file_append_builtin({Value::string(path), Value::string("Line 2\n")});
    
    auto result = file_read_builtin({Value::string(path)});
    EXPECT_EQ(result.as_string(), "Line 1\nLine 2\n");
}

TEST_F(BuiltinFileTest, FileReadlines) {
    std::string path = test_dir + "/lines.txt";
    
    file_write_builtin({Value::string(path), Value::string("Line 1\nLine 2\nLine 3")});
    
    auto result = file_readlines_builtin({Value::string(path)});
    EXPECT_TRUE(result.is_list());
    
    const auto& lines = result.as_list();
    EXPECT_EQ(lines.size(), 3);
    EXPECT_EQ(lines[0].as_string(), "Line 1");
    EXPECT_EQ(lines[1].as_string(), "Line 2");
    EXPECT_EQ(lines[2].as_string(), "Line 3");
}

TEST_F(BuiltinFileTest, FileWritelines) {
    std::string path = test_dir + "/writelines.txt";
    
    Value lines = Value::list();
    lines.as_list().push_back(Value::string("First"));
    lines.as_list().push_back(Value::string("Second"));
    lines.as_list().push_back(Value::string("Third"));
    
    file_writelines_builtin({Value::string(path), lines});
    
    auto result = file_read_builtin({Value::string(path)});
    EXPECT_EQ(result.as_string(), "First\nSecond\nThird\n");
}

TEST_F(BuiltinFileTest, FileReadNonexistent) {
    EXPECT_THROW(
        file_read_builtin({Value::string("nonexistent.txt")}),
        std::runtime_error
    );
}

// ========================================
// 文件属性测试
// ========================================

TEST_F(BuiltinFileTest, FileExists) {
    std::string path = test_dir + "/exists.txt";
    
    auto result1 = file_exists_builtin({Value::string(path)});
    EXPECT_FALSE(result1.as_boolean());
    
    file_write_builtin({Value::string(path), Value::string("test")});
    
    auto result2 = file_exists_builtin({Value::string(path)});
    EXPECT_TRUE(result2.as_boolean());
}

TEST_F(BuiltinFileTest, FileIsfile) {
    std::string file_path = test_dir + "/file.txt";
    std::string dir_path = test_dir + "/subdir";
    
    file_write_builtin({Value::string(file_path), Value::string("test")});
    fs::create_directory(dir_path);
    
    EXPECT_TRUE(file_isfile_builtin({Value::string(file_path)}).as_boolean());
    EXPECT_FALSE(file_isfile_builtin({Value::string(dir_path)}).as_boolean());
}

TEST_F(BuiltinFileTest, FileIsdir) {
    std::string file_path = test_dir + "/file.txt";
    std::string dir_path = test_dir + "/subdir";
    
    file_write_builtin({Value::string(file_path), Value::string("test")});
    fs::create_directory(dir_path);
    
    EXPECT_FALSE(file_isdir_builtin({Value::string(file_path)}).as_boolean());
    EXPECT_TRUE(file_isdir_builtin({Value::string(dir_path)}).as_boolean());
}

TEST_F(BuiltinFileTest, FileSize) {
    std::string path = test_dir + "/size.txt";
    std::string content = "Hello";
    
    file_write_builtin({Value::string(path), Value::string(content)});
    
    auto result = file_size_builtin({Value::string(path)});
    EXPECT_TRUE(result.is_number());
    EXPECT_EQ(result.as_number(), content.size());
}

// ========================================
// 目录操作测试
// ========================================

TEST_F(BuiltinFileTest, DirCreate) {
    std::string dir_path = test_dir + "/newdir";
    
    auto result = dir_create_builtin({Value::string(dir_path)});
    EXPECT_TRUE(result.as_boolean());
    EXPECT_TRUE(fs::exists(dir_path));
    EXPECT_TRUE(fs::is_directory(dir_path));
}

TEST_F(BuiltinFileTest, DirCreateRecursive) {
    std::string dir_path = test_dir + "/a/b/c";
    
    auto result = dir_create_builtin({Value::string(dir_path)});
    EXPECT_TRUE(result.as_boolean());
    EXPECT_TRUE(fs::exists(dir_path));
}

TEST_F(BuiltinFileTest, DirList) {
    std::string dir_path = test_dir + "/listdir";
    fs::create_directory(dir_path);
    
    file_write_builtin({Value::string(dir_path + "/file1.txt"), Value::string("a")});
    file_write_builtin({Value::string(dir_path + "/file2.txt"), Value::string("b")});
    fs::create_directory(dir_path + "/subdir");
    
    auto result = dir_list_builtin({Value::string(dir_path)});
    EXPECT_TRUE(result.is_list());
    
    const auto& entries = result.as_list();
    EXPECT_EQ(entries.size(), 3);
}

TEST_F(BuiltinFileTest, DirRemove) {
    std::string dir_path = test_dir + "/removedir";
    fs::create_directory(dir_path);
    
    auto result = dir_remove_builtin({Value::string(dir_path)});
    EXPECT_TRUE(result.as_boolean());
    EXPECT_FALSE(fs::exists(dir_path));
}

// ========================================
// 文件操作工具测试
// ========================================

TEST_F(BuiltinFileTest, FileCopy) {
    std::string src = test_dir + "/source.txt";
    std::string dst = test_dir + "/dest.txt";
    std::string content = "Copy me";
    
    file_write_builtin({Value::string(src), Value::string(content)});
    
    auto result = file_copy_builtin({Value::string(src), Value::string(dst)});
    EXPECT_TRUE(result.as_boolean());
    EXPECT_TRUE(fs::exists(dst));
    
    auto read_result = file_read_builtin({Value::string(dst)});
    EXPECT_EQ(read_result.as_string(), content);
}

TEST_F(BuiltinFileTest, FileMove) {
    std::string src = test_dir + "/source.txt";
    std::string dst = test_dir + "/moved.txt";
    std::string content = "Move me";
    
    file_write_builtin({Value::string(src), Value::string(content)});
    
    auto result = file_move_builtin({Value::string(src), Value::string(dst)});
    EXPECT_TRUE(result.as_boolean());
    EXPECT_FALSE(fs::exists(src));
    EXPECT_TRUE(fs::exists(dst));
    
    auto read_result = file_read_builtin({Value::string(dst)});
    EXPECT_EQ(read_result.as_string(), content);
}

TEST_F(BuiltinFileTest, FileDelete) {
    std::string path = test_dir + "/delete.txt";
    
    file_write_builtin({Value::string(path), Value::string("test")});
    EXPECT_TRUE(fs::exists(path));
    
    auto result = file_delete_builtin({Value::string(path)});
    EXPECT_TRUE(result.as_boolean());
    EXPECT_FALSE(fs::exists(path));
}

// ========================================
// 错误处理测试
// ========================================

TEST_F(BuiltinFileTest, InvalidArguments) {
    // 参数数量错误
    EXPECT_THROW(file_read_builtin({}), std::runtime_error);
    EXPECT_THROW(file_write_builtin({Value::string("test")}), std::runtime_error);
    
    // 参数类型错误
    EXPECT_THROW(file_read_builtin({Value::make_number(123)}), std::runtime_error);
    EXPECT_THROW(file_write_builtin({Value::string("test"), Value::make_number(123)}), std::runtime_error);
}

TEST_F(BuiltinFileTest, EmptyPath) {
    EXPECT_THROW(file_read_builtin({Value::string("")}), std::runtime_error);
}

} // namespace viml
